use std::sync::Arc;

use crate::RedisError;

use super::{node::NodeSocket, ConnectionState};

pub(crate) struct Shutdown {
    tx: tokio::sync::mpsc::Sender<ShutdownSignal>,
}

impl Shutdown {
    pub(crate) fn new() -> Self {
        let (tx, rx) = tokio::sync::mpsc::channel::<ShutdownSignal>(3);
        tokio::spawn(start_shutdown_wait(rx));
        Self { tx }
    }

    pub(crate) fn clone_tx(&self) -> tokio::sync::mpsc::Sender<ShutdownSignal> {
        self.tx.clone()
    }
}

// #[derive(Clone)]
pub(crate) struct ShutdownSignal {
    reason: ShutdownReason,
    error: Option<RedisError>,
    epoch: u64,
    state: Arc<ConnectionState>,
    socket: Arc<NodeSocket>,
}

impl ShutdownSignal {
    pub(crate) fn new(
        reason: ShutdownReason,
        epoch: u64,
        state: Arc<ConnectionState>,
        socket: Arc<NodeSocket>,
        error: Option<RedisError>,
    ) -> Self {
        Self {
            reason,
            error,
            epoch,
            state,
            socket,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub(crate) enum ShutdownReason {
    // ProtocolError = 0,
    ServerClosed1 = 1,
    ServerClosed2 = 2,
    ServerClosed3 = 3,
    ServerClosed4 = 4,
}

async fn start_shutdown_wait(mut rx: tokio::sync::mpsc::Receiver<ShutdownSignal>) {
    loop {
        match rx.recv().await {
            Some(signal) => {
                if let Some(err) = signal.error {
                    log::error!(
                        "receive shutdown signal, reason = {:?}, epoch = {}, {:?}",
                        signal.reason,
                        signal.epoch,
                        err
                    );
                } else {
                    log::error!(
                        "receive shutdown signal, reason = {:?}, epoch = {}",
                        signal.reason,
                        signal.epoch,
                    );
                }
                super::reconnect(signal.epoch, signal.state, signal.socket).await;
            }
            None => {
                break;
            }
        }
    }
}
